package com.example.myqcloud.oss.cloud;

import cn.hutool.extra.spring.SpringUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.Copy;
import com.qcloud.cos.transfer.TransferManager;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 腾讯云存储
 *
 * @author 江黎
 * @since 2022-05-12
 */
public class QcloudCloudStorageService extends AbstractCloudStorageService {
    private COSCredentials credentials;
    private ClientConfig clientConfig;

    public QcloudCloudStorageService() {
        this.config = SpringUtil.getBean(CloudStorageProperties.class);

        //初始化
        init();
    }

    private void init() {
        //1、初始化用户身份信息(secretId, secretKey)
        credentials = new BasicCOSCredentials(config.getSecretId(), config.getSecretKey());

        //2、设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        clientConfig = new ClientConfig(new Region(config.getRegion()));
    }

    @Override
    public String upload(byte[] data, String path) {
        return upload(new ByteArrayInputStream(data), path);
    }

    @Override
    public String upload(InputStream inputStream, String path) {
        try {
            COSClient client = new COSClient(credentials, clientConfig);

            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(inputStream.available());
            String bucketName = config.getBucketName();
            PutObjectRequest request = new PutObjectRequest(bucketName, path, inputStream, metadata);
            PutObjectResult result = client.putObject(request);

            client.shutdown();
            if (result.getETag() == null) {
                throw new RuntimeException("文件上传失败");
            }
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败");
        }

        return config.getDomain() + "/" + path;
    }

    @Override
    public String uploadSuffix(byte[] data, String suffix) {
        return upload(data, getPath(config.getDefaultPath(), suffix));
    }

    @Override
    public String uploadSuffix(InputStream inputStream, String suffix) {
        return upload(inputStream, getPath(config.getDefaultPath(), suffix));
    }

    @Override
    public void copy(String sourceKey, String targetKey) {
        Region region = new Region(config.getRegion());
        ClientConfig clientConfig = new ClientConfig(region);
        // 这里建议设置使用 https 协议
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 生成 cos 客户端。
        COSClient client = new COSClient(credentials, clientConfig);
        // 初始化 TransferManager
        TransferManager transferManager = new TransferManager(client);

        // 源 Bucket, 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String srcBucketName = config.getBucketName();
        // 生成用于获取源文件信息的 srcCOSClient
        COSClient srcCOSClient = new COSClient(credentials, new ClientConfig(region));
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(region, srcBucketName,
                sourceKey, srcBucketName, targetKey);
        try {
            Copy copy = transferManager.copy(copyObjectRequest, srcCOSClient, null);
            // 返回一个异步结果 copy, 可同步的调用 waitForCopyResult 等待 copy 结束, 成功返回 CopyResult, 失败抛出异常.
            CopyResult copyResult = copy.waitForCopyResult();
            // 获取拷贝生成对象的CRC64
            String crc64Ecma = copyResult.getCrc64Ecma();
        } catch (CosClientException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            client.shutdown();
        }
    }

    @Override
    public void delete(String bucketName, String objectKey) {
        COSClient client = new COSClient(credentials, clientConfig);
        client.deleteObject(bucketName, objectKey);
        client.shutdown();
    }
}